package com.zhanglijie.improve.unsafe;

import java.io.File;
import java.io.FileInputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.nio.file.attribute.UserDefinedFileAttributeView;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;

import javax.jws.soap.SOAPBinding;

import com.zhanglijie.improve.unsafe.domain.Man;
import com.zhanglijie.improve.unsafe.domain.Person;
import com.zhanglijie.improve.unsafe.domain.User;
import com.zhanglijie.theory.threadpermessage.MyServer;

import sun.misc.Unsafe;

/**
 * @author zhanglijie
 * @version 1.0
 * @since 1.1.0 2022/8/16 0016 23:25
 *  1.unsafe类如果  Unsafe.getUnsafe()获得不行 因为这个获取必须类加载器是bootstraper的类加载器
 *  而我们应用是appClassLoader
 *  2.所以获得方式
 *       1.反射
 *       2.将自己应用打成jar包放到bootstrap类加载器搜索范围之内（比如rt.jar)  jvm参数  -Xbootclasspath/a:D:MyUnsafe.jar
 *  这里演示方式一反射方式
 *
 *  -server -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly -XX:-Inline
 */
public class MyUnsafe {
    static AtomicLong atomicLong = new AtomicLong();
    public static void unsafeGetWays() throws  Exception {
        //反射一
        Constructor<?> constructor = Unsafe.class.getDeclaredConstructor() ;
        constructor.setAccessible(true);
        Unsafe unsafe = (Unsafe)constructor.newInstance();
        System.out.println(unsafe);

        //反射二
        Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
        theUnsafe.setAccessible(true);
        Unsafe obj = (Unsafe)theUnsafe.get(null);//静态变量给个null 实例变量给当前实例对象
        System.out.println(obj);
    }


    public static void memoryDemoTwo(){
        System.out.println();
        Unsafe unsafe = getUnsafe();
        int[] arr = {1,2,3,4};
        // int base = unsafe.arrayBaseOffset(int[].class);
        int base =Unsafe.ARRAY_INT_BASE_OFFSET;
        System.out.println("base"+base);//base指的是在填充数据在对象中坐标，
        //一个数组对象（64bit os) 由对象头（markword 8byte 类型指针 4byte) 数组长度 4byte    实例数据 **byte  填充数据构成

        //将数组中第三第四元素都修改16843009
        unsafe.setMemory(arr,base+8,8,(byte)1);//00000001 00000001 00000001 00000001  00000001 00000001 00000001 00000001
        System.out.println(Arrays.toString(arr));//00000001 00000001 00000001 00000001 =16843009

        //将arr拷贝到arr1
        int[] arr1 = {2,2,2,2};
        unsafe.copyMemory(arr,base,arr1,base,16);
        System.out.println(Arrays.toString(arr1));
    }
    public static void memoryDemoOne(){
        Unsafe us= getUnsafe();
        long addr = momerySth(us,16);//底层走malloc
        // System.out.println(addr);
        us.putLong(addr,1234);//在这个地址上存个数字
        System.out.println(us.getLong(addr));
        //拷贝某地址内容到新地址
        long newAddr = momerySth(us,16);

        us.copyMemory(addr,newAddr,16);
        System.out.println(us.getLong(newAddr));

        //重新分配内存 扩容
        us.reallocateMemory(addr, 32);
        // us.setMemory(addr,32,(byte)0);
        // System.out.println(us.getByte(addr));
        us.setMemory(addr,4,(byte)1);//00000001 00000001 00000001 00000001
        System.out.println(us.getInt(addr));//00000001 00000001 00000001 00000001 =16843009
        System.out.println(us.getByte(addr));//00000001
        //释放内存
        us.freeMemory(addr);
        us.freeMemory(newAddr);
    }
    public static Unsafe getUnsafe(){

        try {
            Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
            theUnsafe.setAccessible(true);
            Unsafe obj = (Unsafe) theUnsafe.get(null);//静态变量给个null 实例变量给当前实例对象
            return obj ;
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 分配的堆外内存不受jvm监管
     * @param unsafe
     * @param len 分配内存多少len字节
     * @return
     */
    public static long momerySth(Unsafe unsafe,int len){
        long addr = unsafe.allocateMemory(len);
        System.out.println("分配的内存地址为"+addr);
        return addr;
    }

    public static void arraySth(){
        String [] strs = {"aaa","bbb","ccc"};
        Unsafe unsafe = getUnsafe();
        int base = unsafe.arrayBaseOffset(String[].class);
        System.out.println("string[]实例数据在对象头的start坐标"+base);
        int scale = unsafe.arrayIndexScale(String[].class);//实例数据间隔 （这个是4byte(引用数据类型） 指向常量池字符串）
        System.out.println("string[] 实例数据间隔"+scale);
        long[] longs = {1,2,3};
        int base1 = unsafe.arrayBaseOffset(long[].class);
        System.out.println("long[]实例数据在对象头的start坐标"+base1);
        int scale1 = unsafe.arrayIndexScale(long[].class);//实例数据间隔 （这个是8byte （基本数据类型,但是如果是Long 就是4byte） 指向常量池字符串）
        System.out.println("long[] 实例数据间隔"+scale1);

        //打印 结果
        for (int i = 0; i < strs.length; i++) {
            long baseIndex = base+i*scale;
            System.out.println(unsafe.getObject(strs,baseIndex));
        }

    }
    public static void objOpt() throws InstantiationException, NoSuchFieldException {
        Unsafe unsafe =  getUnsafe();
        Man man = (Man)unsafe.allocateInstance(Man.class);

        Person person = new Person();
        Man zs = new Man("zhagnsan", 2);
        person.setMan(zs);
        person.setId(1);
        long idOffset = unsafe.objectFieldOffset(Person.class.getDeclaredField("id"));
        long manOffset = unsafe.objectFieldOffset(Person.class.getDeclaredField("man"));
        long defaultStrOffset = unsafe.staticFieldOffset(Person.class.getDeclaredField("defaultStr"));
        System.out.println("person id "+unsafe.getInt(person,idOffset));
        System.out.println("person man "+unsafe.getObject(person,manOffset));
        System.out.println("person defaultstr "+unsafe.getObject(Person.class,defaultStrOffset));//静态字段用class

        System.out.println("============update============");
        unsafe.putInt(person,idOffset,22);
        unsafe.putObject(person,manOffset,new Man("lisi",22));
        unsafe.putObject(Person.class,defaultStrOffset,"new Man(\"lisi\",22)_str");
        System.out.println("============updateed after============");
        System.out.println("person id "+unsafe.getInt(person,idOffset));
        System.out.println("person man "+unsafe.getObject(person,manOffset));
        System.out.println("person defaultstr "+unsafe.getObject(Person.class,defaultStrOffset));//静态字段用class

    }

    /**
     * putOrderObject
     * putObjectVolatile
     *
     */
    public static void twoSeconds(){
        // for (int i = 0; i < 100000; i++) {
        //     atomicLong.set(i);//本质上volatile 本质上就是putObjectVolatile    底层lock前缀
        // }

        for (int i = 0; i < 100000; i++) {
            atomicLong.lazySet(i);//本质putOrderedLong
        }
    }

    public static void twoSecondsByUnsafe() throws InstantiationException, NoSuchFieldException {
        Unsafe unsafe =  getUnsafe();
        Man man = (Man)unsafe.allocateInstance(Man.class);

        Person person = new Person();
        Man zs = new Man("zhagnsan", 2);
        person.setMan(zs);
        person.setId(1);
        person.setAddr("zhangzhuang");


        long idOffset = unsafe.objectFieldOffset(Person.class.getDeclaredField("id"));
        long manOffset = unsafe.objectFieldOffset(Person.class.getDeclaredField("man"));
        long addrOffset = unsafe.objectFieldOffset(Person.class.getDeclaredField("addr"));
        long isManOffset = unsafe.objectFieldOffset(Person.class.getDeclaredField("isMan"));

        // for (int i = 0; i < 100000; i++) {
        //     unsafe.putOrderedObject(person,addrOffset,"lijiazhuang");
        // }

        // for (int i = 0; i < 100000; i++) {
        //     unsafe.putObject(person,addrOffset,"lijiazhuang");
        // }
        //
        for (int i = 0; i < 2100000000; i++) {
            unsafe.putObjectVolatile(person,addrOffset,"wangjia");
            unsafe.putObjectVolatile(person,addrOffset,"wansdfgjia");
        }

      //  unsafe.putObjectVolatile(person,addrOffset,"wangjia");
        //System.out.println(unsafe.getObject(person,addrOffset));

    }


    public static void threadLock(){
        Object obj = new Object();
        Unsafe unsafe = getUnsafe();
        new Thread(()->{
            try {
                unsafe.monitorEnter( obj);
            System.out.println(Thread.currentThread().getName()+"  run");
                Thread.sleep(2000);
            }catch (Exception e){}finally {
                unsafe.monitorExit(obj);
            }
        }).start();
        new Thread(()->{
            try {
                unsafe.monitorEnter(obj);
                System.out.println(Thread.currentThread().getName()+"  run");
                Thread.sleep(2000);
            }catch (Exception e){}finally {
                unsafe.monitorExit(obj);
            }
        }).start();

        new Thread(()->{
            try {
                unsafe.monitorEnter(obj);
                System.out.println(Thread.currentThread().getName()+"  run");
                Thread.sleep(2000);
            }catch (Exception e){}finally {
                unsafe.monitorExit(obj);
            }
        }).start();
    }

    /**
     * 演示park unpark 就拿main线程举例子
     * park(true,system.curretntime+阻塞毫秒）
     * park(false,阻塞纳秒）
     * park(false,0) 永久阻塞
     * unpark(thread) 唤醒需要唤醒的线程
     */
    public static void threadParkUnpark() throws InterruptedException {
        System.out.println("running");
        Unsafe unsafe = getUnsafe();
        //阻塞4s
        unsafe.park(true,System.currentTimeMillis()+ TimeUnit.SECONDS.toMillis(4));
        System.out.println("continue run");
        //再阻塞3s
        unsafe.park(false,TimeUnit.SECONDS.toNanos(3));
        System.out.println("will finish");

        Thread thread = new Thread(() -> {
            System.out.println(Thread.currentThread().getName()+" 永久阻塞");
            unsafe.park(false, 0);
        },"per");
        thread.start();

        Thread.sleep(20000);
        unsafe.unpark(thread);
    }

    public static void classOperate() throws Exception {
        User user = new User();
        Unsafe unsafe = getUnsafe();
        boolean b = unsafe.shouldBeInitialized(User.class);
        System.out.println("user initied "+(!b));
        Field name = User.class.getDeclaredField("name");
        long offset = unsafe.staticFieldOffset(name);
        Object classz = unsafe.staticFieldBase(name);
        Object object = unsafe.getObject(classz, offset);
        System.out.println("user.name is "+object);

        System.out.println("动态定义class====================");
        String dir = "D:\\lagouStudy\\juc\\code\\juc\\User.class";
        File file = new File(dir);
        try(FileInputStream fis = new FileInputStream(file)) {
            final byte[] content = new byte[(int) file.length()];
            fis.read(content);
            final Class<?> aClass = unsafe.defineClass(null, content, 0, content.length, null, null);
            final Object o = aClass.newInstance();
            aClass.getMethod("setSex",String.class).invoke(o,"nan");
            final Object getSex = aClass.getMethod("getSex").invoke(o, null);
            System.out.println(getSex);

            final Class<?> aClass1 = unsafe.defineAnonymousClass(User.class, content, null);
            System.out.println("匿名方式获得class +"+aClass1);
        }catch (Exception e){
            System.out.println(e);
        }

    }

    public static void fence(){
       //这个已经在之前写过了
    }
    public static void systemInfo(){
        final Unsafe unsafe = getUnsafe();
        final int i = unsafe.addressSize();
        final int i1 = unsafe.pageSize();
        System.out.println(i);
        System.out.println(i1);
    }
    public static void main(String[] args) throws Exception {

        //twoSecondsByUnsafe();
        //twoSeconds();
        // threadLock();
        //threadParkUnpark();
        systemInfo();
    }
}
